package cn.com.jdyun.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import org.springframework.beans.factory.annotation.Value;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Date;

/**
 * @author yzping
 * @date Created in 下午 3:25 2018/9/14 0014
 */
public class TokenUtils {

    private static String SECRET_HEAD = "JIDIANYUN-";

    @Value("${secret.text}")
    private static String SECRET_TEXT;

    @Value("${secret.issuer}")
    private static String ISSUER;

    public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException {

        String token = createJWT("abc", 3600 * 1000L);
        System.out.println("token:" + token);
        parseJWT(token);
    }
    /**
     * 创建一个token
     *
     * @param subject
     * @param ttlMillis
     * @return
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     */
    public static String createJWT(String subject, long ttlMillis) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        //The JWT signature algorithm we will be using to sign the token
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        //Let's set the JWT Claims
        JwtBuilder builder = Jwts.builder().setIssuedAt(now)
                .setSubject(subject)
                .setIssuer(ISSUER)
                .signWith(signatureAlgorithm, generalKey());

        //if it has been specified, let's add the expiration
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }

        //Builds the JWT and serializes it to a compact, URL-safe string
        return builder.compact();
    }

    /**
     * 读取token
     *
     * @param jwt
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     * @throws IllegalArgumentException
     * @throws SignatureException
     * @throws MalformedJwtException
     * @throws UnsupportedJwtException
     * @throws ExpiredJwtException
     */
    public static Claims parseJWT(String jwt) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException, UnsupportedEncodingException, NoSuchAlgorithmException {

        //This line will throw an exception if it is not a signed JWS (as expected)
        Claims claims = Jwts.parser()
                .setSigningKey(generalKey())
                .parseClaimsJws(jwt).getBody();
        return claims;
    }


    private static String HEXAndMd5(String plainText) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            try {
                md.update(plainText.getBytes("UTF8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer(200);
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset] & 0xff;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            return buf.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    private static SecretKey generalKey() throws UnsupportedEncodingException, NoSuchAlgorithmException {

        String stringKey = HEXAndMd5(SECRET_HEAD + SECRET_TEXT);

        byte[] encodedKey = Base64.getEncoder().encode(stringKey.getBytes());

        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");

        return key;

    }


}
